
* Replication syntax for
* "Voice and Balancing in US Congressional Elections"
* by Till Weber, published in Perspectives on Politics

clear all
cd YOUR_DIRECTORY_HERE
use replic_voicebalancing_data.dta


*** Table 1

	* frequencies
tab ideology midterm if _mi_m>0 [aw=weight], col nof
tab partisanship midterm if _mi_m>0 [aw=weight], col nof
tab crossed_groups midterm if _mi_m>0 [aw=weight], col nof

	* generate dummies
qui tab ideology, gen(ideology_)
qui tab partisanship, gen(partisanship_)
qui tab crossed_groups, gen(crossed_groups_)
mi reg imp ideology_* crossed_groups_*

	* install program by Daniel Klein to compute margins from mi data
ssc install mimrgns

	* standard errors
foreach var of varlist ideology_* partisanship_* crossed_groups_* {
    di "`var'"
	qui mi est: probit `var' i.midterm [pw=weight], cl(year)
	mimrgns, dydx(midterm) pr(pr)
}


*** Table 2

	* frequencies
tabstat inparty_official if count==1 & _mi_m==0, by(midterm)
bysort ideology: tab choice_inparty midterm if _mi_m>0 [aw=weight], col nof
bysort partisanship: tab choice_inparty midterm if _mi_m>0 [aw=weight], col nof
bysort crossed_groups: tab choice_inparty midterm if _mi_m>0 [aw=weight], col nof

	* standard errors
foreach var of varlist ideology_* partisanship_* crossed_groups_* {
    di "`var'"
	qui mi est, esampvaryok: probit choice_inparty i.midterm if `var'==1 [pw=weight], cl(year)
	mimrgns, dydx(midterm) esampvaryok pr(pr)
}


*** Table 3

	* frequencies
tabstat turnout_official if count==1 & _mi_m==0, by(midterm)
bysort ideology: tab voted midterm if _mi_m>0 [aw=weight], col nof
bysort partisanship: tab voted midterm if _mi_m>0 [aw=weight], col nof
bysort crossed_groups: tab voted midterm if _mi_m>0 [aw=weight], col nof

	* standard errors
foreach var of varlist ideology_* partisanship_* crossed_groups_* {
    di "`var'"
	qui mi est, esampvaryok: probit voted i.midterm if `var'==1 [pw=weight], cl(year)
	mimrgns, dydx(midterm) esampvaryok pr(pr)
}


*** Change to macro level

	* collapse data
keep if crossed_groups==1
bysort _mi_m year: egen choice_inparty_perc = wtmean(choice_inparty*100), weight(weight)
bysort _mi_m year: egen voted_perc = wtmean(voted*100), weight(weight)
bysort _mi_m year: gen aux = _n
keep if aux==1
drop aux

	* restore original (empty) copy for imputed years
expand 2 if year<1972 & _mi_m==1, gen(aux)
replace _mi_m = 0 if aux==1
replace choice_inparty_perc = . if aux==1
replace voted_perc = . if aux==1
drop aux

	* set as panel to connect midterm to preceding on-year
mi unset, asis
gen imp = _mi_m
drop _mi_m _mi_id _mi_miss
xtset imp year, delta(2)

	* generate midterm variables (D=difference, L=lag, M=mean)
gen Linparty_official = l.inparty_official if midterm==1
gen Lchoice_inparty_perc = l.choice_inparty_perc if midterm==1
gen Dchoice_inparty_perc = d.choice_inparty_perc if midterm==1
gen Dvoted_perc = d.voted_perc if midterm==1
gen gallup_change = gallup_dem_vote-l.inparty_official if presidents_party==1 & midterm==1
replace gallup_change = gallup_rep_vote-l.inparty_official if presidents_party==2 & midterm==1
gen Lgallup_pres_lead = l.gallup_dem_votepres-l.gallup_rep_votepres if presidents_party==1 & midterm==1
replace Lgallup_pres_lead = l.gallup_rep_votepres-l.gallup_dem_votepres if presidents_party==2 & midterm==1
bysort year: egen Mchoice_inparty_perc = mean(choice_inparty_perc) if imp>0
bysort year: egen MLchoice_inparty_perc = mean(Lchoice_inparty_perc) if imp>0
bysort year: egen MDchoice_inparty_perc = mean(Dchoice_inparty_perc) if imp>0
gen Lyear = year-2

	* restore multiple imputation setting
xtset, clear
mi import flong, m(imp) id(year) imp(*choice_inparty_perc *voted_perc) clear


*** Figure 1

gen labpos = 12 if midterm==0
replace labpos = 6 if midterm==1
replace labpos = 6 if inlist(year,1956,1984,2004,2008)
replace labpos = 12 if inlist(year,1958,1986,2006,2010)

sc Mchoice_inparty_perc year, mlab(year) mlabc(black) mlabvp(labpos) mc(black) msize(small) || /*
*/ pcarrow MLchoice_inparty_perc Lyear Mchoice_inparty_perc year if midterm==1, /*
*/ lc(gray) mc(gray) msize(large) lw(medthick) mlw(medthick) /*
*/ xlab(1955 2020, labsize(3.5)) ylab(40(10)100, labsize(3.5) gmin gmax) /*
*/ xti("Election year", size(3.5)) xsca(titlegap(-1)) /*
*/ yti("Percent of in-party support among torn partisans", size(3.5)) ysca(titlegap(2)) /*
*/ xsize(8) legend(off) graphr(c(white)) xline(1961(8)2017, lw(31pt) lc(gs14%50) noex)


*** Table 4

	* M1
mi est: reg Dchoice_inparty_perc ib2.presidents_term gallup_change if midterm==1, r

	* M2
mi est: reg Dchoice_inparty_perc Dvoted_perc if midterm==1, r

	* M3
mi est: reg Dvoted_perc ib2.presidents_term gallup_change if midterm==1, r


*** Figure 2

	* need manual procedure to pass mi results to margins and marginsplot (as described in https://stats.idre.ucla.edu/stata/faq/how-can-i-get-margins-and-marginsplot-with-multiply-imputed-data/)

pr mir, rclass
    ret add
    ret mat b=b
    ret mat V=V
end

pr emarg1, eclass prop(mi)
	vers 16
	reg Dchoice_inparty_perc ib2.presidents_term gallup_change if midterm==1, r
	margins, at(gallup_change=(-15(3)3) presidents_term=(1 2)) post
end

qui mi est: reg Dchoice_inparty_perc ib2.presidents_term gallup_change if midterm==1, r

qui mi est, cmdok: emarg1
mat b = e(b_mi)
mat V = e(V_mi)

qui reg Dchoice_inparty_perc ib2.presidents_term gallup_change if midterm==1 & _mi_m==0, r
qui margins, at(gallup_change=(-15(3)3) presidents_term=(1 2))

mir
mata: st_global("e(cmd)", "margins")

marginsplot, x(gallup_change) plotopts(msymbol(none) lc(black) xl(-15(3)3, labs(3.5)) yl(-40(10)40, labs(3.5) gmin gmax) /*
*/ ysc(noline) xsc(noline) xti("Midterm change of in-party support suggested by Gallup", size(3.5)) xsca(titlegap(2)) /*
*/ yti("Actual midterm change among torn partisans", size(3.5)) ysca(titlegap(2)) legend(off)) /*
*/ recastci(rline) ciopts(lc(black) lp(dash) lc(gray)) ti("") /*
*/ text(29.5 -13.7 "2nd term", size(3.5) box m(tiny)) text(-10 -10 "1st term", size(3.5) box m(tiny)) /*
*/ addplot(sc MDchoice_inparty_perc gallup_change if midterm==1 & imp==1, /*
*/ mlab(year) mlabc(black) mlabs(3.5) ms(i) mlabp(0) xlab(-15(3)3)) graphr(fc(white))


*** Table 5

	* generate variables
gen party_polarization = nominate_dim1_medianHR-nominate_dim1_medianHD
gen presidents_extremeness = abs(nominate_dim1_medianP)
gen gallup_valence_diff = gallup_dem_valence-gallup_rep_valence if presidents_party==1
replace gallup_valence_diff = gallup_rep_valence-gallup_dem_valence if presidents_party==2

	* M4
mi est: reg Dchoice_inparty_perc ib2.presidents_term gallup_change presidents_extremeness party_polarization if midterm==1, r

	* M5
mi est: reg Dchoice_inparty_perc (ib2.presidents_term c.gallup_change)##c.presidents_extremeness if midterm==1, r

	* M6
mi est: reg Dchoice_inparty_perc (ib2.presidents_term c.gallup_change)##c.party_polarization if midterm==1, r

	* M7
mi est: reg Dchoice_inparty_perc ib2.presidents_term gallup_change Lchoice_inparty_perc Lgallup_pres_lead if midterm==1, r

	* M8
mi est: reg Dchoice_inparty_perc ib2.presidents_term gallup_change Linparty_official gallup_pres_approval gallup_valence_diff if midterm==1, r


*** Figure 3a

pr emarg2, eclass prop(mi)
  vers 16
  reg Dchoice_inparty_perc (ib2.presidents_term c.gallup_change)##c.presidents_extremeness if midterm==1, r
  margins, dydx(presidents_term) at(presidents_extremeness=(.25(.05).7)) post
end

qui mi est: reg Dchoice_inparty_perc (ib2.presidents_term c.gallup_change)##c.presidents_extremeness if midterm==1, r

qui mi est, cmdok: emarg2
mat b= e(b_mi)
mat V = e(V_mi)

qui reg Dchoice_inparty_perc (ib2.presidents_term c.gallup_change)##c.presidents_extremeness if midterm==1 & _mi_m==0, r
qui margins, dydx(presidents_term) at(presidents_extremeness=(.25(.05).7))

mir
mata: st_global("e(cmd)", "margins")

marginsplot, plotopts(msymbol(none) lc(black) lw(thick) xl(.25(.05).7, labs(4.5)) yl(-60(15)30, labs(4.5) gmin gmax) /*
*/ ysc(noline) xsc(noline) xti("President's extremeness in DW-NOMINATE", size(5)) xsca(titlegap(2)) /*
*/ yti("Marginal effect of first term", size(5)) ysca(titlegap(2)) legend(off)) /*
*/ recastci(rline) ciopts(lc(black) lp(dash) lc(gray) lw(thick)) yli(0, lc(black) lw(thin)) /*
*/ ti("(a) Effect of first term over president’s extremeness", margin(b=5) c(black) s(5)) graphr(fc(white))


*** Figure 3b

pr emarg3, eclass prop(mi)
  vers 16
  reg Dchoice_inparty_perc (ib2.presidents_term c.gallup_change)##c.party_polarization if midterm==1, r
  margins, dydx(gallup_change) at(party_polarization=(.55(.05).9)) post
end

qui mi est: reg Dchoice_inparty_perc (ib2.presidents_term c.gallup_change)##c.party_polarization if midterm==1, r

qui mi est, cmdok: emarg3
mat b= e(b_mi)
mat V = e(V_mi)

qui reg Dchoice_inparty_perc (ib2.presidents_term c.gallup_change)##c.party_polarization if midterm==1 & _mi_m==0, r
qui margins, dydx(gallup_change) at(party_polarization=(.55(.05).9))

mir
mata: st_global("e(cmd)", "margins")

marginsplot, plotopts(msymbol(none) lc(black) lw(thick) xl(.55(.05).9, labs(4.5)) yl(-6(2)6, labs(4.5) gmin gmax) /*
*/ ysc(noline) xsc(noline) xti("Party polarization in DW-NOMINATE", size(5)) xsca(titlegap(2)) /*
*/ yti("Marginal effect of Gallup estimate", size(5)) ysca(titlegap(2)) legend(off)) /*
*/ recastci(rline) ciopts(lc(black) lp(dash) lc(gray) lw(thick)) yli(0, lc(black) lw(thin)) /*
*/ ti("(b) Effect of Gallup estimate over party polarization", margin(b=5) c(black) s(5)) graphr(fc(white))


*** Additional documentation

view browse https://cunycorn.wordpress.com/category/statisticorn/
